﻿using CoreBluetooth;
using Foundation;
using MauiControl.Models;
using MauiControl.Services;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace MauiControl.Platforms.iOS.Services
{
    public class BluetoothServiceiOS : IBluetoothService, IDisposable
    {
        public static class Uuids
        {
            public const string Service = "0000ae30-0000-1000-8000-00805f9b34fb";
            public const string Write = "0000ae01-0000-1000-8000-00805f9b34fb";
            public const string Notify = "0000ae02-0000-1000-8000-00805f9b34fb";

            public const string GenericAccess = "00001800-0000-1000-8000-00805f9b34fb";
            public const string DeviceName = "00002a00-0000-1000-8000-00805f9b34fb";
            public const string BatteryService = "0000180f-0000-1000-8000-00805f9b34fb";
            public const string BatteryLevel = "00002a19-0000-1000-8000-00805f9b34fb";
        }

        private CBCentralManager _centralManager;
        private List<BleDeviceInfo> _devices;
        private TaskCompletionSource<List<BleDeviceInfo>> _searchCompletionSource;
        private Action<BleDeviceInfo> _onDeviceAddedCallback;
        private readonly Dictionary<string, CBPeripheral> _discoveredDevices = new();

        private CBPeripheral _connectedPeripheral;
        private CBCharacteristic _sendCharacteristic;
        private CBCharacteristic _receiveCharacteristic;
        private bool _isConnected = false;
        private object _lockObject = new object();
        private bool _disposed = false;
        private bool _isRunning = false;
        private CancellationTokenSource _cancellationTokenSource;

        public BluetoothServiceiOS()
        {
            _devices = new List<BleDeviceInfo>();
            _centralManager = new CBCentralManager();

            _centralManager.DiscoveredPeripheral += OnDiscoveredPeripheral;
            _centralManager.UpdatedState += OnUpdatedState;
            _centralManager.ConnectedPeripheral += OnConnectedPeripheral;
            _centralManager.DisconnectedPeripheral += OnDisconnectedPeripheral;
        }

        public async Task<List<BleDeviceInfo>> SearchDevicesAsync(CancellationToken cancellationToken, Action<BleDeviceInfo> onDeviceAddedCallback)
        {
            _devices.Clear();
            _discoveredDevices.Clear();

            _searchCompletionSource = new TaskCompletionSource<List<BleDeviceInfo>>();
            _onDeviceAddedCallback = onDeviceAddedCallback;

            _centralManager.ScanForPeripherals((CBUUID)null);

            cancellationToken.Register(() =>
            {
                _centralManager.StopScan();
                _searchCompletionSource.TrySetCanceled();
            });

            try
            {
                await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);
                _centralManager.StopScan();
                return _devices;
            }
            catch (TaskCanceledException)
            {
                _centralManager.StopScan();
                throw new OperationCanceledException("设备搜索已取消。");
            }
            catch (Exception ex)
            {
                _centralManager.StopScan();
                throw new Exception($"设备搜索失败: {ex.Message}");
            }
        }

        private void OnDiscoveredPeripheral(object sender, CBDiscoveredPeripheralEventArgs e)
        {
            var deviceName = e.Peripheral.Name ?? "未知设备";
            var deviceId = e.Peripheral.Identifier.ToString();

            var device = new BleDeviceInfo(
                name: deviceName,
                address: deviceId, // 使用 UUID 作为设备地址
                macAddress: deviceId, // 使用 UUID 作为格式化后的 MAC 地址
                platformSpecificId: deviceId // 使用 UUID 作为平台特定标识符
            );

            if (!_discoveredDevices.ContainsKey(deviceId))
            {
                _discoveredDevices[deviceId] = e.Peripheral;
                _devices.Add(device);
                _onDeviceAddedCallback?.Invoke(device);
            }
        }

        private void OnUpdatedState(object sender, EventArgs e)
        {
            if (_centralManager.State == CBManagerState.PoweredOn)
            {
                Debug.WriteLine("蓝牙已打开。");
            }
            else
            {
                Debug.WriteLine("蓝牙未打开或不可用。");
            }
        }

        public async Task<BleDeviceInfo> ConnectDeviceAsync(string deviceId)
        {
            int retryCount = 6;
            for (int i = 0; i < retryCount; i++)
            {
                try
                {
                    Debug.WriteLine($"尝试连接设备，设备ID: {deviceId} (尝试次数: {i + 1})");

                    if (!_discoveredDevices.ContainsKey(deviceId))
                    {
                        throw new KeyNotFoundException($"未找到地址为 {deviceId} 的设备。");
                    }

                    var peripheral = _discoveredDevices[deviceId];
                    Debug.WriteLine($"设备名称: {peripheral.Name}");

                    if (_connectedPeripheral != null && _connectedPeripheral.State == CBPeripheralState.Connected)
                    {
                        Disconnect();
                    }

                    _connectedPeripheral = peripheral;
                    _centralManager.ConnectPeripheral(_connectedPeripheral);

                    await Task.Delay(2000);

                    Debug.WriteLine($"设备连接状态: {_connectedPeripheral.State}");

                    await DiscoverServicesAndCharacteristicsAsync();

                    await WriteDataAsync(new byte[] { 0x29 });
                    Debug.WriteLine("保持连接指令 (0x29) 发送成功。");

                    await EnableNotificationAsync();

                    string batteryLevel = await GetBatteryLevelAsync(deviceId);

                    return new BleDeviceInfo(peripheral.Name, deviceId, deviceId, deviceId)
                    {
                        BatteryLevel = batteryLevel // 更新电量信息
                    };
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"连接设备时出错: {ex.Message}");
                    if (i == retryCount - 1)
                    {
                        throw;
                    }
                    await Task.Delay(1000);
                }
            }

            throw new Exception("多次尝试后仍无法连接设备。");
        }

        private async Task DiscoverServicesAndCharacteristicsAsync()
        {
            _connectedPeripheral.DiscoverServices(new CBUUID[] { CBUUID.FromString(Uuids.Service) });

            await Task.Delay(1000);

            var targetService = _connectedPeripheral.Services?.FirstOrDefault(s => s.UUID.ToString() == Uuids.Service);
            if (targetService == null)
            {
                Debug.WriteLine("未找到目标服务。");
                throw new Exception("未找到目标服务。");
            }

            _connectedPeripheral.DiscoverCharacteristics(new CBUUID[] { CBUUID.FromString(Uuids.Write), CBUUID.FromString(Uuids.Notify) }, targetService);

            await Task.Delay(1000);

            _sendCharacteristic = targetService.Characteristics?.FirstOrDefault(c => c.UUID.ToString() == Uuids.Write);
            _receiveCharacteristic = targetService.Characteristics?.FirstOrDefault(c => c.UUID.ToString() == Uuids.Notify);

            if (_sendCharacteristic == null || _receiveCharacteristic == null)
            {
                Debug.WriteLine("未找到目标特征。");
                throw new Exception("未找到目标特征。");
            }
        }

        private async Task EnableNotificationAsync()
        {
            _connectedPeripheral.SetNotifyValue(true, _receiveCharacteristic);
            await Task.Delay(500);
        }

        public async Task<byte[]> ReadRawDataAsync()
        {
            if (_receiveCharacteristic == null)
            {
                throw new InvalidOperationException("未找到接收特征。");
            }

            try
            {
                _connectedPeripheral.ReadValue(_receiveCharacteristic);
                await Task.Delay(500);

                var rawData = _receiveCharacteristic.Value?.ToArray();
                if (rawData == null)
                {
                    throw new Exception("读取到的数据为空。");
                }

                Debug.WriteLine($"读取到的原始数据: {BitConverter.ToString(rawData)}");
                return rawData;
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"读取数据时出错: {ex.Message}");
                throw;
            }
        }

        public async Task WriteDataAsync(byte[] data)
        {
            if (_sendCharacteristic == null)
            {
                throw new InvalidOperationException("未找到发送特征。");
            }

            try
            {
                _connectedPeripheral.WriteValue(NSData.FromArray(data), _sendCharacteristic, CBCharacteristicWriteType.WithoutResponse);
                await Task.Delay(500);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"写入数据时出错: {ex.Message}");
                throw;
            }
        }

        public void Disconnect()
        {
            lock (_lockObject)
            {
                if (!_isConnected || _disposed) return;
                _isConnected = false;
            }

            try
            {
                StopReadingData();

                if (_connectedPeripheral != null)
                {
                    _centralManager.CancelPeripheralConnection(_connectedPeripheral);
                    _connectedPeripheral.Dispose();
                    _connectedPeripheral = null;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"断开连接时出错: {ex.Message}");
            }
        }

        private void OnConnectedPeripheral(object sender, CBPeripheralEventArgs e)
        {
            Debug.WriteLine("设备已连接。");
            _isConnected = true;
        }

        private void OnDisconnectedPeripheral(object sender, CBPeripheralErrorEventArgs e)
        {
            Debug.WriteLine("设备已断开连接。");
            Disconnect();
            _ = AttemptReconnectAsync();
        }

        private async Task AttemptReconnectAsync()
        {
            await Task.Delay(TimeSpan.FromSeconds(5));
            try
            {
                if (_connectedPeripheral != null)
                {
                    await ConnectDeviceAsync(_connectedPeripheral.Identifier.ToString());
                    Debug.WriteLine("重新连接成功。");
                }
                else
                {
                    Debug.WriteLine("无法重新连接：未设置最后连接的设备。");
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"重新连接尝试失败: {ex.Message}");
            }
        }

        public async Task<string> GetBatteryLevelAsync(string deviceId)
        {
            try
            {
                var batteryServiceUuid = CBUUID.FromString(Uuids.BatteryService);
                var batteryLevelCharacteristicUuid = CBUUID.FromString(Uuids.BatteryLevel);

                _connectedPeripheral.DiscoverServices(new CBUUID[] { batteryServiceUuid });
                await Task.Delay(1000);

                var batteryService = _connectedPeripheral.Services?.FirstOrDefault(s => s.UUID == batteryServiceUuid);
                if (batteryService == null)
                {
                    Debug.WriteLine("未找到电池服务。");
                    return "N/A";
                }

                _connectedPeripheral.DiscoverCharacteristics(new CBUUID[] { batteryLevelCharacteristicUuid }, batteryService);
                await Task.Delay(1000);

                var batteryLevelCharacteristic = batteryService.Characteristics?.FirstOrDefault(c => c.UUID == batteryLevelCharacteristicUuid);
                if (batteryLevelCharacteristic == null)
                {
                    Debug.WriteLine("未找到电量特征。");
                    return "N/A";
                }

                _connectedPeripheral.ReadValue(batteryLevelCharacteristic);
                await Task.Delay(500);

                var batteryLevel = batteryLevelCharacteristic.Value?[0] ?? 0;
                return $"{batteryLevel}%";
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"读取电量信息时出错: {ex.Message}");
                return "N/A";
            }
        }

        public void StartReadingData()
        {
            if (_isRunning) return;

            _isRunning = true;
            _cancellationTokenSource = new CancellationTokenSource();

            Task.Run(async () => await ReadSensorDataLoop(_cancellationTokenSource.Token));
        }

        public void StopReadingData()
        {
            _isRunning = false;
            _cancellationTokenSource?.Cancel();
        }

        private async Task ReadSensorDataLoop(CancellationToken cancellationToken)
        {
            while (_isRunning && !cancellationToken.IsCancellationRequested)
            {
                try
                {
                    if (_connectedPeripheral == null || _connectedPeripheral.State != CBPeripheralState.Connected)
                    {
                        Debug.WriteLine("设备未连接，停止读取数据。");
                        break;
                    }

                    var sensorData = await ReadSensorDataAsync();
                    Debug.WriteLine($"读取到的传感器数据: {sensorData}");
                    await Task.Delay(100, cancellationToken);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"读取传感器数据时出错: {ex.Message}");
                }
            }
        }

        public async Task<SensorData> ReadSensorDataAsync()
        {
            if (_receiveCharacteristic == null)
            {
                throw new InvalidOperationException("未找到接收特征。");
            }

            _connectedPeripheral.ReadValue(_receiveCharacteristic);
            await Task.Delay(500);

            var rawData = _receiveCharacteristic.Value?.ToArray();
            if (rawData == null)
            {
                throw new Exception("读取到的数据为空。");
            }

            float[] imuData = ParseImu(rawData);
            if (imuData == null)
            {
                throw new Exception("Failed to parse IMU data.");
            }

            return new SensorData
            {
                AccelX = imuData[0],
                AccelY = imuData[1],
                AccelZ = imuData[2],
                AngularVelX = imuData[6],
                AngularVelY = imuData[7],
                AngularVelZ = imuData[8],
                QuaternionW = imuData[15],
                QuaternionX = imuData[16],
                QuaternionY = imuData[17],
                QuaternionZ = imuData[18],
                EulerX = imuData[19],
                EulerY = imuData[20],
                EulerZ = imuData[21]
            };
        }

        private float[] ParseImu(byte[] buf)
        {
            const float scaleAccel = 0.00478515625f;
            const float scaleAngle = 0.0054931640625f;
            const float scaleAngleSpeed = 0.06103515625f;
            const float scaleMag = 0.15106201171875f;
            const float scaleTemperature = 0.01f;
            const float scaleAirPressure = 0.0002384185791f;
            const float scaleHeight = 0.0010728836f;
            const float scaleQuat = 0.000030517578125f;
            var imuDat = new float[34];
            if (buf[0] == 0x11)
            {
                int l = 7;
                ushort ctl = (ushort)((buf[2] << 8) | buf[1]);
                if ((ctl & 0x0001) != 0)
                {
                    imuDat[0] = BitConverter.ToInt16(buf, l) * scaleAccel; l += 2;
                    imuDat[1] = BitConverter.ToInt16(buf, l) * scaleAccel; l += 2;
                    imuDat[2] = BitConverter.ToInt16(buf, l) * scaleAccel; l += 2;
                }
                if ((ctl & 0x0002) != 0)
                {
                    imuDat[3] = BitConverter.ToInt16(buf, l) * scaleAccel; l += 2;
                    imuDat[4] = BitConverter.ToInt16(buf, l) * scaleAccel; l += 2;
                    imuDat[5] = BitConverter.ToInt16(buf, l) * scaleAccel; l += 2;
                }
                if ((ctl & 0x0004) != 0)
                {
                    imuDat[6] = BitConverter.ToInt16(buf, l) * scaleAngleSpeed; l += 2;
                    imuDat[7] = BitConverter.ToInt16(buf, l) * scaleAngleSpeed; l += 2;
                    imuDat[8] = BitConverter.ToInt16(buf, l) * scaleAngleSpeed; l += 2;
                }
                if ((ctl & 0x0008) != 0)
                {
                    imuDat[9] = BitConverter.ToInt16(buf, l) * scaleMag; l += 2;
                    imuDat[10] = BitConverter.ToInt16(buf, l) * scaleMag; l += 2;
                    imuDat[11] = BitConverter.ToInt16(buf, l) * scaleMag; l += 2;
                }
                if ((ctl & 0x0010) != 0)
                {
                    imuDat[12] = BitConverter.ToInt16(buf, l) * scaleTemperature; l += 2;
                    var tmpU32 = BitConverter.ToInt32(buf, l) & 0x00FFFFFF;
                    if ((tmpU32 & 0x800000) != 0) tmpU32 |= unchecked((int)0xFF000000);
                    imuDat[13] = tmpU32 * scaleAirPressure; l += 3;
                    tmpU32 = BitConverter.ToInt32(buf, l) & 0x00FFFFFF;
                    if ((tmpU32 & 0x800000) != 0) tmpU32 |= unchecked((int)0xFF000000);
                    imuDat[14] = tmpU32 * scaleHeight; l += 3;
                }
                if ((ctl & 0x0020) != 0)
                {
                    imuDat[15] = BitConverter.ToInt16(buf, l) * scaleQuat; l += 2;
                    imuDat[16] = BitConverter.ToInt16(buf, l) * scaleQuat; l += 2;
                    imuDat[17] = BitConverter.ToInt16(buf, l) * scaleQuat; l += 2;
                    imuDat[18] = BitConverter.ToInt16(buf, l) * scaleQuat; l += 2;
                }
                if ((ctl & 0x0040) != 0)
                {
                    imuDat[19] = BitConverter.ToInt16(buf, l) * scaleAngle; l += 2;
                    imuDat[20] = BitConverter.ToInt16(buf, l) * scaleAngle; l += 2;
                    imuDat[21] = BitConverter.ToInt16(buf, l) * scaleAngle; l += 2;
                }
                return imuDat;
            }
            return null;
        }

        public void Dispose()
        {
            lock (_lockObject)
            {
                if (_disposed) return;
                _disposed = true;

                if (_connectedPeripheral != null)
                {
                    _connectedPeripheral.Dispose();
                    _connectedPeripheral = null;
                }

                if (_centralManager != null)
                {
                    _centralManager.DiscoveredPeripheral -= OnDiscoveredPeripheral;
                    _centralManager.UpdatedState -= OnUpdatedState;
                    _centralManager.ConnectedPeripheral -= OnConnectedPeripheral;
                    _centralManager.DisconnectedPeripheral -= OnDisconnectedPeripheral;
                    _centralManager.Dispose();
                    _centralManager = null;
                }
            }
        }
    }
}